package com.hz.house.service;

import com.alibaba.fastjson.JSON;
import com.hz.house.bean.entity.CustomerBean;
import com.hz.house.bean.entity.SellManScoreBean;
import com.hz.house.bean.entity.SellmanScoreConsumeRecord;
import com.hz.house.bean.vo.SellManCachedBasicInfoBean;
import com.hz.house.common.Constants;
import com.hz.house.common.wxmini.Value;
import com.hz.house.common.wxmini.WxMaSubscribeMessage;
import com.hz.house.dao.AddScoreMapper;
import com.hz.house.dao.CustomerMapper;
import com.hz.house.dao.SellManMapper;
import com.hz.house.enums.ScoreConsumeTypeEnum;
import com.hz.house.enums.SellManScoreEnum;
import com.hz.house.enums.SystemMsgEnum;
import com.hz.house.utils.DaysIntUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p> 置业顾问积分系统业务
 *
 * @author lfw
 */
@Service
@Slf4j
public class SellManScoreService {

    @Autowired
    private RedisCacheDataService cacheService;

    @Autowired
    private AddScoreMapper addScoreMapper;

    @Autowired
    private SellManMapper sellManMapper;

    @Autowired
    private CustomerMapper userMapper;

    @Autowired
    private SysMsgService sysMsgService;

    @Autowired
    private WxgzhSellHouseService wxgzhSellHouseService;

    @Autowired
    private WxMaSubscribeService wxMaSubscribeService;

    /**
     * @param info      加分项信息
     */
    @Transactional(rollbackFor = Throwable.class)
    public void addScoreOnShare(SellManScoreBean info) {
        long st = System.currentTimeMillis();
        //加分项是否存在
        SellManScoreEnum s = SellManScoreEnum.getSellManScoreEnumById(info.getScoreId());
        if (s == null) {
            log.info("加分项不存在,加分失败!");
            return;
        }

        //2019-12-26日取消分享时间限制
//		if(sharedate!=DaysIntUtil.getDays(new Date())) {
//			log.info("分享加分已经过期，只有当天内24点前有效!");
//			return;
//		}
        if (info.getCustomerId().intValue() == info.getSellManCustomerId()) {
            log.info("置业顾问自己点击分享页面加分无效!");
            return;
        }
        //用户是不是置业顾问
        int sellManCustomerId = info.getSellManCustomerId();
        if (cacheService.getSellManBasicInfo(sellManCustomerId) == null) {
            log.info("用户:" + sellManCustomerId + "不是置业顾问,无法加分!");
            return;
        }
        //触发加分的普通用户是否今天已经帮别人点击分享页面加过分了
        //上线第二天修改：将加分条件调整为一个用户可以为多个人点击加分，只能为同一个用户分享的不同页面加一次分，sssssbbbbbb
        //long index = cacheService.setCustomerIdForRepeat(info.getCustomerId());
        String uniqueId = getRepeatString(s.getId(), info.getCustomerId(), info.getSellManCustomerId());
        long index = cacheService.setCustomerId_ScoreId_SellmanIdForRepeat(uniqueId);
        if (index == 0) {
            log.info("用户:" + info.getCustomerId() + "已经给该置业顾问的该分享页面加过分了!");
            return;
        }
        //查询用户是新用户还是老用户，然后使用redis进行限额计数
        int isNew = addScoreMapper.getIsNewCustomer(info.getCustomerId(), sellManCustomerId, Constants.SCENEID_SELLMAN_SHARE);
        //查询并记录+1，如果后面加分失败也不减了 ，算他倒霉
        boolean isOverLimit = isOverLimit(isNew, sellManCustomerId);
        if (isOverLimit) {
            log.info("置业顾问:" + sellManCustomerId + "已经到达分享加分项的限制!");
            //将用户从临时表删除
            this.cacheService.removeCustomerIdForRepeat(info.getCustomerId());
            return;
        }
        if (isNew > 0) {
            info.setScore(10);
            log.info("新用户点击置业顾问分享页面啦...");
        } else {
			info.setScore(5);
		}
        //执行分享加分并记录加分记录和计算相关联系数据
		//第3次调库
        doAddScore(info);
        long ed = System.currentTimeMillis();
        log.info("置业顾问分享页面被点击加分完成,耗时:" + (ed - st) + "ms!");
    }

    /**
     * 返回唯一的组合
     */
    private String getRepeatString(int scoreId, int customerId, int sellmanId) {
        return scoreId + "_" + customerId + "_" + sellmanId;
    }

    //执行加分
    private void doAddScore(SellManScoreBean info) {
        log.info("执行加分:" + JSON.toJSONString(info));
        //加分记录表加分
        int index = this.addScoreMapper.addScoreRecord(info);
        if (index == 0) {
            log.info("加分记录插入失败,加分失败");
            return;
        }
        //总积分累加，修改相关值
        int res = this.addScoreMapper.updateSellManScoreItem(info);
        if (res == 0) {
            log.info("置业顾问总分值修改失败!");
            return;
        }
        CustomerBean customer = this.userMapper.getCustomerById(info.getSellManCustomerId());

        //微信公众号发送
//        Map<String, Object> data = new HashMap<>();
//        wxgzhSellHouseService.sendAddSourceMsg(customer.getOpenid(), data);

        WxMaSubscribeMessage wxMaSubscribeMessage = new WxMaSubscribeMessage();
        wxMaSubscribeMessage.setTouser(customer.getOpenid());
        wxMaSubscribeMessage.setPage(wxMaSubscribeService.SCORE_DETAIL_PAGE);
        wxMaSubscribeMessage.setTemplate_id(wxMaSubscribeService.SCORE_DETAIL_TEMPLATE_CODE);
        Map<String, Value> params = new HashMap<>(16);
        params.put("thing1", new Value("尊敬的置业顾问你好"));
        params.put("number2", new Value(String.valueOf(addScoreMapper.getConsultantTotalScore(info.getSellManCustomerId()))));
        //当前加分类型
        SellManScoreEnum scoreEnum = SellManScoreEnum.getSellManScoreEnumById(info.getScoreId());
        params.put("thing3", new Value(scoreEnum.getName() + "进行了加分!"));
        params.put("number5", new Value(String.valueOf(info.getScore())));
        params.put("thing6", new Value("详情进入小程序了解！"));
        wxMaSubscribeMessage.setData(params);
        log.info("小程序发送订阅消息:{}", JSON.toJSONString(wxMaSubscribeMessage));
        //小程序推送订阅消息
        wxMaSubscribeService.sendSubscribeMsg(wxMaSubscribeMessage);

        //站内推送
        String title = "积分变动提示";
        String content = "通过" + scoreEnum.getName() + "进行了加分!+" + info.getScore();
        sysMsgService.sendSysMsg(info.getSellManCustomerId(), content, title, "type=integral", SystemMsgEnum.SHAR);
    }

    /**
     * 判定置业顾问加分项是否超限,true超限，false未超限
     */
    private boolean isOverLimit(int isNew, int sellManCustomerId) {
        String type = isNew > 0 ? "share_new" : "share_old";
        int limitStandard = isNew > 0 ? 100 : 20;
        Long limit = this.cacheService.getSellManAddScoreLimitNow(sellManCustomerId, type, limitStandard);
        if (limit == -1) {
            cacheService.initSellManAddScoreLimit(sellManCustomerId, type);
            limit = 1L;
        }
        return limit == 0;
    }

    /**
     * <p> 在关注成都卖房帮手后加分，防止用户并发不断取关再关注来刷分
     *
     * @param info
     */

    //防止快速操作关注后造成并发加分
    private Map<String, Object> addScoreOnFocusWxgzhLockers = new ConcurrentHashMap<>();

    public void addScoreOnFocusWxgzh(SellManScoreBean info) {
        if (info == null)
            return;
        if (info.getScoreId() != SellManScoreEnum.FOUCS_WXGZH_SELLMAN.getId())
            return;
        Object locker = addScoreOnFocusWxgzhLockers.get(info.getSellManCustomerId() + "");
        if (locker == null)
            addScoreOnFocusWxgzhLockers.put(info.getSellManCustomerId() + "", locker = new Object());
        synchronized (locker) {
            //查询是否已经关注过加过分了，如果取关再关注则不加分
            try {
                int index = this.addScoreMapper.getIsAddFoucusWxgzh(info.getSellManCustomerId(), info.getScoreId());
                if (index > 0) {
                    log.info("关注公众号加分,已经加过了,重复取关无效!");
                    return;
                }
                //执行加分
                doAddScore(info);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("关注卖房帮手公众号加分异常", e);
            } finally {
                addScoreOnFocusWxgzhLockers.remove(info.getSellManCustomerId() + "");
            }
        }
    }

    /**
     * <p>加分，当置业顾问被普通用户关注时，防止快速点击关注取消刷分并发加分
     *
     * @param info
     */
    private Map<String, Object> addScoreOnBeFocused = new ConcurrentHashMap<>();

    public void addScoreOnBeFocused(SellManScoreBean info) {
        if (info == null)
            return;
        if (info.getScoreId() != SellManScoreEnum.BE_FOCUSED.getId())
            return;
        Object locker = addScoreOnBeFocused.get(info.getCustomerId() + "");//普通用户的操作
        if (locker == null)
            addScoreOnBeFocused.put(info.getCustomerId() + "", locker = new Object());
        //防止快速操作刷分
        synchronized (locker) {
            try {
                int index = this.addScoreMapper.getIsAddFoucused(info.getSellManCustomerId()
                        , info.getScoreId(), info.getCustomerId());
                if (index > 0) {
                    log.info("置业顾问被关注加分已经重复，无法重复加分!");
                    return;
                }
                //执行加分
                doAddScore(info);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("置业顾问被关注加分异常", e);
            } finally {
                addScoreOnBeFocused.remove(info.getCustomerId() + "");
            }
        }
    }


    /**
     * <p>在置业顾问回复自家楼盘下的评论时加分
     *
     * @param info
     */
    public void addScoreOnReplyComment(SellManScoreBean info, int buildingId) {
        if (info == null)
            return;
        if (info.getScoreId() != SellManScoreEnum.BUILDING_COMMENT_REPLY.getId())
            return;
        SellManCachedBasicInfoBean sm = this.cacheService.getSellManBasicInfo(info.getSellManCustomerId());
        if (sm == null)
            return;//不是置业顾问
        if (sm.getBuildingId().intValue() != buildingId)
            return;//自家的楼盘下回复才加分
        //查看是否超过每日限制
        Long limit = this.cacheService.getSellManAddScoreLimitNow(info.getSellManCustomerId(),
                "comment_reply", SellManScoreEnum.BUILDING_COMMENT_REPLY.getLimit());
        if (limit == -1) {
            this.cacheService.initSellManAddScoreLimit(info.getSellManCustomerId(), "comment_reply");
            limit = 1l;
        }
        if (limit == 0) {
            log.info("置业顾问回复楼盘评论加分超过每日次数限制!");
            return;
        }
        //执行加分
        doAddScore(info);
    }

    /**
     * 修改连续获取积分的天数
     */
    public void updateSeriesGetScoreDays() throws Exception {
        try {
            int nowDays = DaysIntUtil.getDays(new Date());
            this.addScoreMapper.updateSeriesGetScoreDays(nowDays);
        } catch (Exception e) {
            log.error("更新连续获取积分时间天数异常", e);
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * <p> 置业顾问签到加积分
     *
     * @param info
     */
    public void addScoreOnSign(SellManScoreBean info) {

        if (info == null)
            return;
        SellManScoreEnum sign = SellManScoreEnum.getSellManScoreEnumById(info.getScoreId());
        if (sign == null)
            return;
        if (sign.getId() != SellManScoreEnum.SELL_MAN_SIGN.getId())
            return;

        //由签到业务去控制是否并发重复，此处不处理了
        //执行加分
        doAddScore(info);

    }

    /**
     * <p> 置业顾问签到30天加积分
     *
     * @param info
     */
    public void addScoreOnSign30Days(SellManScoreBean info) {

        if (info == null)
            return;
        SellManScoreEnum sign = SellManScoreEnum.getSellManScoreEnumById(info.getScoreId());
        if (sign == null)
            return;
        if (sign.getId() != SellManScoreEnum.SIGN_30_DAYS.getId())
            return;
        //由签到业务去控制是否并发重复，此处不处理了
        //执行加分
        doAddScore(info);

    }

    /**
     * <p> 置业顾问签到7天加积分
     *
     * @param info
     */
    public void addScoreOnSign7Days(SellManScoreBean info) {

        if (info == null)
            return;
        SellManScoreEnum sign = SellManScoreEnum.getSellManScoreEnumById(info.getScoreId());
        if (sign == null)
            return;
        if (sign.getId() != SellManScoreEnum.SIGN_7_DAYS.getId())
            return;
        //由签到业务去控制是否并发重复，此处不处理了
        //执行加分
        doAddScore(info);

    }

    /**
     * 积分消费
     *
     * @param sellManCustomerId
     * @param score
     * @param minusType
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void minusScore(int sellManCustomerId, int score, ScoreConsumeTypeEnum minusType) throws Exception {
        if (score < 1)
            throw new Exception("扣减积分失败");
        //先扣减积分
        int x = sellManMapper.minusScore(sellManCustomerId, score);
        if (x < 1)
            throw new Exception("扣减积分失败，积分不足");
        //添加扣减记录
        SellmanScoreConsumeRecord r = new SellmanScoreConsumeRecord();
        r.setCreateTime(new Date());
        r.setCustomerId(sellManCustomerId);
        r.setMinusScore(score);
        r.setMinusScoreType(minusType.getId());
        int index = this.sellManMapper.addMinusScoreRecord(r);
        if (index < 1)
            throw new Exception("添加积分消费记录失败");
    }

}
